import { ConfigService } from '@nestjs/config';
import { UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { StrategyOptions, Strategy, ExtractJwt } from 'passport-jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from 'src/system/user/entities/user.entity';
import { AuthService } from './auth.service';
import { RedisService } from 'src/db/redis-cache.service';
import { MenuService } from 'src/system/menu/menu.service';

export class JwtStorage extends PassportStrategy(Strategy) {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly configService: ConfigService,
    private readonly authService: AuthService,
    private readonly redisService: RedisService,
    private readonly menu: MenuService,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: configService.get('SECRET'),
      passReqToCallback: true,
    } as StrategyOptions);
  }

  async validate(req, user: User) {
    interface CacheTokenObj {
      token: string;
      ua: object;
      ip: string;
      ipAddress: string;
      user: User;
      loginTime: Date;
      token_id: string;
    }
    // 获取请求头中的token
    const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
    // 获取redis中该用户的最新token
    const cacheTokenObj: CacheTokenObj | string = await this.redisService.get(
      `login_token:${token}`,
    );
    let cacheToken: string = '';
    let newLoginToken = {};
    if (typeof cacheTokenObj === 'object' && cacheTokenObj !== null) {
      cacheToken = (cacheTokenObj as CacheTokenObj).token;
      newLoginToken = {
        ua: (cacheTokenObj as CacheTokenObj).ua,
        ip: (cacheTokenObj as CacheTokenObj).ip,
        token,
        ipAddress: (cacheTokenObj as CacheTokenObj).ipAddress,
        user: (cacheTokenObj as CacheTokenObj).user,
        loginTime: (cacheTokenObj as CacheTokenObj).loginTime,
        token_id: (cacheTokenObj as CacheTokenObj).token_id,
      };
      // 使用 cacheToken
    } else {
      console.error('cacheTokenObj 不是有效的对象');
    }

    if (!cacheToken) {
      throw new UnauthorizedException('token 已过期');
    }
    if (token != cacheToken) {
      throw new UnauthorizedException('token不正确');
    }
    const exitUser = await this.authService.getUser(user);
    if (!exitUser) {
      throw new UnauthorizedException('token不正确');
    }

    //token自动续期30分钟
    this.redisService.set(
      `login_token:${token}`,
      newLoginToken,
      this.configService.get('REDIS_TIMEOUT'),
    );

    // 当用户存在时，会将 user 对象添加到 req 中，在之后的 req 对象中，可以使用 req.user 获取当前登录用户。
    let permissions = await this.menu.getPerms(exitUser.id);
    return {
      ...exitUser,
      permissions,
    };
  }
}
